home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
MCASM.RAR
/
MC_ASM.EXE
/
WROX_ASM
/
CH10
/
PROGRAMS
/
LZW1.ASM
< prev
next >
Wrap
Assembly Source File
|
1994-05-30
|
15KB
|
712 lines
; Compile with TASM 3.0 and latter.
; TASM lzw1.asm /MX /ZX /O
; CALL: lzw_encode(char *buffinput,int lenginput,char *buffoutput);
; CALL: lzw_decode(char *buffinput,int lenginput,char *buffoutput);
MODEL large
.386
PUBLIC _lzw_encode
PUBLIC _lzw_decode
INIT_BITS EQU 9
MAX_BITS EQU 13 ; The number of the BITS
HASHING_SHIFT EQU MAX_BITS - 8
; The size of the table
; Depends on MAX_BITS TABLE_SIZE
; 13 9029
; 14 18041
; else 5021
TABLE_SIZE EQU 9029
CLEAR_TABLE EQU 256 ; Code to flush the string table
TERMINATOR EQU 257 ; LZW EOF char
FIRST_CODE EQU 258 ; First code for array_code
CHECK_TIME EQU 100 ; Check comp ratio every CHECK_TIME chars input
.DATA
inputbuffer dd ?
outputbuffer dd ?
inputleng dw ?
array_code1 dd ?
array_prefix1 dd ?
array_character1 dd ?
decode_stack dw 4000 dup(?)
;This array holds the decoded string
num_bits dw INIT_BITS ; Starting with 9 bit codes
;unsigned long bytes_in=0,bytes_out=0 /* Used to monitor compression ratio */
bytes_in dd 0
bytes_out dd 0
max_code dw ? ; old MAX_CODE
;unsigned long checkpoint=CHECK_TIME /* For compression ratio monitoring */
checkpoint dd CHECK_TIME
output_bit_buffer dd 0
output_bit_count dw 0
input_bit_buffer dd 0
input_bit_count dw 0
input_ptr dw ? ; Positions in the buffers
output_ptr dw ?
.CODE
MAXVAL PROC NEAR
PUSH CX
MOV CX,AX
MOV AX,1
SHL AX,CL
DEC AX
POP CX
RET
MAXVAL ENDP
_lzw_encode PROC C FAR
ARG ibuf:dword,ilng:word,obuf:dword
LOCAL next_code:word,character:word,string_code:word,\
index:word,ratio_new:word,ratio_old:word
USES bx,cx,dx,di,si,es,ds
mov ax,@DATA
mov ds,ax
mov bx,TABLE_SIZE ; Allocate memory
mov cl,3 ; bx*2/16
shr bx,cl
inc bx
mov ah,48h
int 21h
jnc @@mem_aloc_020
jmp @@mem_aloc_err
@@mem_aloc_020: mov word ptr array_code1+2,ax
mov word ptr array_code1,0
mov bx,TABLE_SIZE
mov cl,3
shr bx,cl
inc bx
mov ah,48h
int 21h
jnc @@mem_aloc_030
jmp @@mem_aloc_er1
@@mem_aloc_030: mov word ptr array_prefix1+2,ax
mov word ptr array_prefix1,0
mov bx,TABLE_SIZE
mov cl,3
shr bx,cl
inc bx
mov ah,48h
int 21h
jnc @@mem_aloc_040
jmp @@mem_aloc_er2
@@mem_aloc_040: mov word ptr array_character1+2,ax
mov word ptr array_character1,0
mov eax,ibuf ; Initialize segments
mov inputbuffer,eax
mov eax,obuf
mov outputbuffer,eax
mov ax,ilng
mov inputleng,ax
mov bytes_in,0
mov bytes_out,0
mov checkpoint,CHECK_TIME
mov output_bit_buffer,0
mov output_bit_count,0
mov input_bit_buffer,0
mov input_bit_count,0
mov num_bits,INIT_BITS
mov ax,word ptr array_code1+2
mov es,ax
mov input_ptr,0
mov output_ptr,0
mov ax,num_bits
call MAXVAL
mov max_code,ax
mov ax,FIRST_CODE
mov next_code,ax
mov ax,100
mov ratio_old,ax
; Initialize the string table first
mov cx,TABLE_SIZE
mov ax,word ptr array_code1+2
mov es,ax
mov di,word ptr array_code1
mov ax,-1
cld
rep stosw
; Get the first code
; Read byte from ax. Return - ah - eof=0 else =1, al - byte.
call getc
xor ah,ah
mov string_code,ax
; Main compression loop
@@main_comp_010:call getc
cmp ah,0
jne @@main_comp_020
; Exit from main_comp.
jmp @@main_comp_090
@@main_comp_020:xor ah,ah
mov character,ax
inc dword ptr bytes_in
mov ax,string_code
mov bx,character
call find_match C,ax,bx
mov index,ax
mov bx,ax
shl bx,1
mov di,bx
add di,word ptr array_code1
mov ax,word ptr array_code1+2
mov es,ax
mov ax,word ptr es:[di] ; bx*2
cmp ax,-1
je @@main_comp_030
mov string_code,ax
jmp @@main_comp_080
@@main_comp_030:mov ax,next_code
cmp ax,max_code
ja @@main_comp_040
mov word ptr es:[di],ax
inc word ptr next_code
mov di,bx
add di,word ptr array_prefix1
mov ax,word ptr array_prefix1+2
mov es,ax
mov ax,string_code
mov word ptr es:[di],ax
mov di,bx
add di,word ptr array_character1
mov ax,word ptr array_character1+2
mov es,ax
mov ax,character
mov word ptr es:[di],ax
@@main_comp_040:
; Send out current code
mov ax,string_code
call output_code C,ax
mov ax,character
mov string_code,ax
; Is table Full?
mov ax,next_code
cmp ax,max_code
ja @@main_comp_045
jmp @@main_comp_080
@@main_comp_045:
; Any more bits?
mov ax,num_bits
cmp ax,MAX_BITS
jae @@main_comp_050
; Increment code size then
inc ax
mov num_bits,ax
call MAXVAL
mov max_code,ax
jmp @@main_comp_080
; At checkpoint?
@@main_comp_050: mov ax,word ptr bytes_in+2
mov dx,word ptr bytes_in
cmp ax,word ptr checkpoint+2
jae @@main_comp_055
jmp @@main_comp_080
@@main_comp_055: cmp dx,word ptr checkpoint
ja @@main_comp_056
jmp @@main_comp_080
@@main_comp_056: mov bx,num_bits
cmp bx,MAX_BITS
jne @@main_comp_070
mov ax,word ptr bytes_out
mov cx,100
mul cx
mov cx,word ptr bytes_in
div cx
; New compression ratio
mov word ptr ratio_new,ax
; Has ratio degraded?
cmp ax,ratio_old
jbe @@main_comp_060
; YES,flush string table
mov ax,CLEAR_TABLE
call output_code C,ax
mov num_bits,INIT_BITS
; Reset to FIRST_CODE
mov next_code,FIRST_CODE
; Re-Initialize this stuff
mov ax,num_bits
call MAXVAL
mov max_code,ax
xor ax,ax
mov word ptr bytes_in,ax
mov word ptr bytes_in+2,ax
mov word ptr bytes_out,ax
mov word ptr bytes_out+2,ax
; Reset compression ratio
mov ax,100
mov ratio_old,ax
; Reset code value array
mov cx,TABLE_SIZE
mov di,word ptr array_code1
mov ax,word ptr array_code1+2
mov es,ax
mov ax,-1
cld
rep stosw
jmp short @@main_comp_070
; NO, then save new compression ratio
@@main_comp_060: mov ratio_old,ax
; Set new checkpoint
@@main_comp_070: mov eax,bytes_in
add eax,CHECK_TIME
mov checkpoint,eax
@@main_comp_080:
jmp @@main_comp_010
; Output the last code
@@main_comp_090:mov ax,string_code
call output_code C,ax
; Handles special case for bit
mov bx,next_code
cmp bx,max_code
jne @@main_comp_100
; increment on EOF
inc word ptr num_bits
; Output the end of buffer code
@@main_comp_100:mov ax,TERMINATOR
call output_code C,ax
; Flush the output buffer
xor bx,bx
call output_code C,bx
call output_code C,bx
call output_code C,bx
mov ax,word ptr array_character1+2
call free_memory
mov ax,word ptr array_prefix1+2
call free_memory
mov ax,word ptr array_code1+2
call free_memory
mov ax,output_ptr
ret
@@mem_aloc_er2: mov ax,word ptr array_prefix1+2
call free_memory
@@mem_aloc_er1: mov ax,word ptr array_code1+2
call free_memory
@@mem_aloc_err: xor ax,ax
ret
; This is the hashing routine.
find_match PROC C NEAR
; Return AX
ARG hash_prefix:word,hash_character:word
LOCAL index:word,foffset:word
USES bx,cx,di,si
mov ax,hash_character
mov cx,HASHING_SHIFT
shl ax,cl
xor ax,hash_prefix
mov index,ax
cmp ax,0
jne @@find_mtch_010
mov bx,1
mov foffset,bx
jmp short @@find_mtch_020
@@find_mtch_010: mov bx,TABLE_SIZE
sub bx,ax
mov foffset,bx
@@find_mtch_020:mov bx,word ptr array_code1+2
mov es,bx
mov bx,ax
mov di,ax
shl di,1
mov si,di
add di,word ptr array_code1
mov ax,-1
cmp ax,word ptr es:[di]
jne @@find_mtch_030
mov ax,bx
ret
@@find_mtch_030:mov di,si
add di,word ptr array_prefix1
mov ax,word ptr array_prefix1+2
mov es,ax
mov ax,word ptr es:[di]
cmp ax,hash_prefix
jne @@find_mtch_040
mov di,si
add di,word ptr array_character1
mov ax,word ptr array_character1+2
mov es,ax
mov ax,word ptr es:[di]
cmp ax,hash_character
jne @@find_mtch_040
mov ax,bx
ret
@@find_mtch_040:sub bx,foffset
cmp bx,0
jge @@find_mtch_050
add bx,TABLE_SIZE
@@find_mtch_050:mov index,bx
mov ax,bx
jmp @@find_mtch_020
find_match ENDP
; Output a variable length code.
output_code PROC C NEAR
ARG ocode:word
LOCAL output_var:dword
USES ax,bx,cx,dx
mov eax,output_bit_buffer
mov bx,ocode
mov word ptr output_var,bx
xor bx,bx
mov word ptr output_var+2,bx
mov ebx,output_var
mov cx,32
sub cx,num_bits
sub cx,output_bit_count
shl ebx,cl
or eax,ebx
mov output_bit_buffer,eax
mov bx,output_bit_count
add bx,num_bits
mov output_bit_count,bx
@@output_010: cmp bx,8
jb @@output_020
mov eax,output_bit_buffer
mov cl,24
shr eax,cl
call putc C,ax
mov eax,output_bit_buffer
mov cl,8
shl eax,cl
mov output_bit_buffer,eax
sub bx,8
mov output_bit_count,bx
inc dword ptr bytes_out
jmp short @@output_010
@@output_020: ret
output_code ENDP
_lzw_encode ENDP
; LZW decompressor
_lzw_decode PROC C FAR
ARG ibuf:dword,ilng:word,obuf:dword
LOCAL next_code:word,new_code:word,old_code:word,\
character:word,counter:word,clear_flag:word,\
string:word
USES bx,cx,dx,di,si,ds,es
mov ax,@data
mov ds,ax
mov bx,TABLE_SIZE
mov cl,3
shr bx,cl
inc bx
mov ah,48h
int 21h
jnc @@dem_aloc_030
jmp @@dem_aloc_err
@@dem_aloc_030: mov word ptr array_prefix1+2,ax
mov word ptr array_prefix1,0
mov bx,TABLE_SIZE
mov cl,3
shr bx,cl
inc bx
mov ah,48h
int 21h
jnc @@dem_aloc_040
jmp @@dem_aloc_er2
@@dem_aloc_040: mov word ptr array_character1+2,ax
mov word ptr array_character1,0
mov bytes_in,0
mov bytes_out,0
mov checkpoint,CHECK_TIME
mov output_bit_buffer,0
mov output_bit_count,0
mov input_bit_buffer,0
mov input_bit_count,0
mov num_bits,INIT_BITS
mov eax,ibuf ; Initialize segments
mov inputbuffer,eax
mov ax,ilng
mov inputleng,ax
mov eax,obuf
mov outputbuffer,eax
mov input_ptr,0
mov output_ptr,0
mov ax,INIT_BITS
mov num_bits,ax
call MAXVAL
mov max_code,ax
mov next_code,FIRST_CODE
mov counter,0
; Need to clear the code value array
mov clear_flag,1
@@expand_000: call input_code
mov new_code,ax
cmp ax,TERMINATOR
jne @@expand_010
jmp @@expand_100
; Initialize or Re-Initialize
@@expand_010: mov ax,clear_flag
cmp ax,1
jne @@expand_020
mov clear_flag,0
mov ax,new_code
mov old_code,ax
mov character,ax
call putc C,ax
jmp @@expand_000
; Clear string table
@@expand_020: mov ax,new_code
cmp ax,CLEAR_TABLE
jne @@expand_030
mov clear_flag,1
mov ax,INIT_BITS
mov num_bits,ax
mov next_code,FIRST_CODE
call MAXVAL
mov max_code,ax
jmp @@expand_000
@@expand_030: mov ax,counter
inc ax
cmp ax,1000
jne @@expand_040
xor ax,ax
@@expand_040: mov counter,ax
; Check for string+char+string
mov ax,new_code
cmp ax,next_code
jb @@expand_050
mov ax,character
mov decode_stack[0],ax
mov bx,old_code
mov ax,2
call decode_string C,ax,bx
mov string,ax
jmp short @@expand_060
@@expand_050: xor ax,ax
mov bx,new_code
call decode_string C,ax,bx
mov string,ax
; Output decoded string in reverse
@@expand_060: mov bx,string
mov di,bx
mov ax,decode_stack[di]
mov character,ax
@@expand_070: cmp bx,0
jl @@expand_080
mov di,bx
mov cx,decode_stack[di]
call putc C,cx
sub bx,2
jmp short @@expand_070
@@expand_080: mov string,bx
; Add to string table if not full
mov bx,next_code
cmp bx,max_code
ja @@expand_090
mov di,bx
shl di,1
mov si,di
add di,word ptr array_prefix1
mov ax,word ptr array_prefix1+2
mov es,ax
mov ax,old_code
mov word ptr es:[di],ax
mov di,si
add di,word ptr array_character1
mov ax,word ptr array_character1+2
mov es,ax
mov ax,character
mov word ptr es:[di],ax
inc bx
mov next_code,bx
cmp bx,max_code
jne @@expand_090
mov ax,num_bits
cmp ax,MAX_BITS
jae @@expand_090
inc ax
mov num_bits,ax
call MAXVAL
mov max_code,ax
@@expand_090: mov ax,new_code
mov old_code,ax
jmp @@expand_000
@@expand_100: mov ax,word ptr array_character1+2
call free_memory
mov ax,word ptr array_prefix1+2
call free_memory
mov ax,output_ptr
ret
@@dem_aloc_er2: mov ax,word ptr array_prefix1+2
call free_memory
@@dem_aloc_err: xor ax,ax
ret
; Decode a string from the string table, storing it in a buffer.
; The buffer can then be output in reverse order by the expansion
; program.
decode_string PROC C NEAR
ARG buffer:word,ocode:word
USES bx,cx,dx,si,di
mov bx,buffer
xor cx,cx
@@dec_str_000: mov dx,ocode
cmp dx,255
jbe @@dec_str_010
mov di,dx
shl di,1
mov si,di
add di,word ptr array_character1
mov ax,word ptr array_character1+2
mov es,ax
mov ax,word ptr es:[di]
mov decode_stack[bx],ax
add bx,2
mov di,si
add di,word ptr array_prefix1
mov ax,word ptr array_prefix1+2
mov es,ax
mov ax,word ptr es:[di]
mov dx,ax
mov ocode,ax
cmp cx,4000
jb @@dec_str_000
mov ax,4c01h
int 21h
@@dec_str_010: mov di,bx
mov ax,ocode
mov decode_stack[di],ax
mov ax,bx
ret
decode_string ENDP
; Input a variable length code.
input_code PROC C NEAR
LOCAL return_value:word,input_var:dword
USES bx,cx
mov ax,input_bit_count
@@input_010: cmp ax,24
ja @@input_020
xor ax,ax
mov word ptr input_var+2,ax
call getc
xor ah,ah
mov word ptr input_var,ax
mov eax,input_var
mov cx,24
sub cx,input_bit_count
shl eax,cl
or input_bit_buffer,eax
mov ax,8
add ax,input_bit_count
mov input_bit_count,ax
jmp @@input_010
@@input_020: mov cx,32
sub cx,num_bits
mov eax,input_bit_buffer
shr eax,cl
mov return_value,ax
mov cx,num_bits
mov eax,input_bit_buffer
shl eax,cl
mov input_bit_buffer,eax
mov ax,num_bits
sub input_bit_count,ax
mov ax,return_value
ret
input_code ENDP
_lzw_decode ENDP
; Get char
getc PROC C NEAR
USES bx,di,es
; Return : EOF - ah=0 else ah=1, al=byte
xor ax,ax
mov bx,input_ptr
cmp bx,inputleng
jae @@getc_eof
mov ax,word ptr inputbuffer+2
mov es,ax
mov di,word ptr inputbuffer
mov al,byte ptr es:[bx+di]
inc word ptr input_ptr
mov ah,1
@@getc_eof: ret
getc ENDP
; Put char
putc PROC C NEAR
ARG character:byte
USES ax,bx,di,es
mov bx,output_ptr
mov ax,word ptr outputbuffer+2
mov es,ax
mov di,word ptr outputbuffer
mov al,character
mov byte ptr es:[bx+di],al
inc word ptr output_ptr
ret
putc ENDP
; Procedure for free memory.
; INPUT: AX=segment adress (paragraph) of memory to realease.
free_memory PROC NEAR
mov bx,ax
mov ah,49h
mov es,bx
int 21h
ret
free_memory ENDP
END